/**
 * Created by jinxs on 14-6-26.
 * 修改自easyUI
 */
(function ($) {
    var _cacheName = 'draggable';

    /**
    * @class 拖拽组件
    * @constructor draggable
    * @summary 构造函数
    * @param [options] {Object|String} 组件配置参数|要调用的组件方法名
    * @param [param] {Object} 表示要调用的方法的参数
    * @example
    * // 构件组件
    * $('#div').draggable({
    *      axis:'h',
    *      onStopDrag: function(e){
    *          alert(this[0]==e.data.target[0]);
    *      }
    * });
    * // 调用组件方法options
    * $('#div').draggable("options");
    */
    $.fn.draggable = function (options, param) {
        if (typeof options == 'string') {
            return $.fn.draggable.methods[options](this, param);
        }
        return this.each(function(){
            var me = $(this);
            var cache = me.data(_cacheName);
            var opts;

            options = options || {};
            if (cache) {
                cache.handle.unbind('.draggable');
                opts = $.extend(cache.options, options);
            } else {
                opts = $.extend({}, $.fn.draggable.defaults,me.parseUIConfig(), options);
            }
            var handle = opts.handle ? (typeof opts.handle == 'string' ? $(opts.handle, me) : opts.handle) : me;

            me.data(_cacheName, {
                options: opts,
                handle: handle
            });

            if (opts.disabled) {
                me.css('cursor', '');
                return;
            }

            handle.unbind('.draggable')
                .bind('mouseover.draggable', {target: me}, function (e) {
                    if ($.fn.draggable.isDragging){return}
                    $('body').css('cursor', opts.cursor);
                })
                .bind('mouseleave.draggable', {target: me}, function (e) {
                    $('body').css('cursor', '');
                })
                .bind('mousemove.draggable', {target: me}, function (e) {
                    $.fn.draggable.mousemove = true;
                })
                .bind('mousedown.draggable', {target: me}, function (e) {
                    var target = e.data.target;
                    var parent = target.parent();
                    var scrollLeft = parent.scrollLeft();
                    var scrollTop = parent.scrollTop();
                    var position = target.position();
                    var offset = target.offset();
                    var doc=$(document);
                    var data = {
                        startPosition: target.css('position'),
                        startLeft: position.left + scrollLeft,
                        startTop: position.top + scrollTop,
                        left: position.left,
                        top: position.top,
                        startX: e.pageX,
                        startY: e.pageY,
                        offsetWidth: (e.pageX - offset.left),
                        offsetHeight: (e.pageY - offset.top),
                        target: target,
                        parent: parent[0]
                    };

                    $.fn.draggable.mousedown = true;
                    $.extend(e.data, data);
                    var opts = target.data(_cacheName).options;
                    if (opts.onBeforeDrag.call(target, e) == false) return;

                    doc.bind('mousedown.draggable', e.data, _doDown);
                    doc.bind('mousemove.draggable', e.data, _doMove);
                    doc.bind('mouseup.draggable', e.data, _doUp);

                    $.fn.draggable.timer = setTimeout(function(){
                        $.fn.draggable.isDragging = true;
                        _doDown(e);
                    }, opts.delay);
                    return false;
                });
        });
    };

    $.fn.draggable.isDragging = false;

    /**
     * 方法
     * @lends draggable.prototype
     */
    $.fn.draggable.methods = {
        /**
         * @summary 获得组件的配置对象
         * @name draggable#options
         * @function
         * @returns {Object} 组件的配置对象
         */
        options: function (target) {
            return $.data(target[0], _cacheName).options;
        },
        /**
         * @summary 获得拖拽对象的代理
         * @name draggable#proxy
         * @function
         * @returns {jQuery} 拖拽对象的代理
         */
        proxy: function (target) {
            return $.data(target[0], _cacheName).proxy;
        },
        /**
         * @summary 启用拖拽
         * @name draggable#enable
         * @function
         * @returns {jQuery} 方法调用者
         * @example
         * $('#div').draggable("enable")
         * 或
         * $('#div').draggable({disabled: false})
         */
        enable: function (target) {
            return target.draggable({disabled: false});
        },
        /**
         * @summary 禁用拖拽
         * @name draggable#disable
         * @function
         * @returns {jQuery} 方法调用者
         */
        disable: function (target) {
            return target.draggable({disabled: true});
        }
    };
    /**
     * 默认配置
     * @lends draggable.prototype
     */
    $.fn.draggable.defaults = {
        /**
         * @type String|Function
         * @default null
         * @summary 拖拽的代理对象
         * @example
         * // 以#div下的#head为代理对象
         * $("#div").draggable({
         *      proxy:"#head"
         * });
         * // 等同于
         * $("#div").draggable({
         *      proxy: function(){
         *          return this.find("#head");
         *      }
         * });
         */
        proxy: null,
        /**
         * 拖动时鼠标样式
         * @type String
         * @default "move"
         */
        cursor:'move',
        delay:100,
        /**
         * @type Boolean
         * @default false
         * @summary 指示拖拽后是否回到初始位置
         */
        revert: false,
        /**
         * @type Number
         * @default null
         * @summary 拖拽的X方向步长
         */
        deltaX: null,
        /**
         * @type Number
         * @default null
         * @summary 拖拽的Y方向步长
         */
        deltaY: null,
        /**
         * @type String|jQuery
         * @default null
         * @summary 拖拽的对象
         */
        handle: null,
        /**
         * @type Boolean
         * @default false
         * @summary 是否禁用
         */
        disabled: false,
        edge: 0,
        /**
         * 值可以为v, h, vh
         * @type String
         * @default "vh"
         * @summary 可拖拽的方向
         */
        axis: 'vh',

        /**
         * 可通过返回false取消拖拽动作
         * @summary 在对象开始拖拽前触发的方法。
         * @event
         * @name draggable#onBeforeDrag
         * @param e {Object} 事件对象
         * @this jQuery对象
         * @default emptyFn
         */
        onBeforeDrag: function (e) {
        },
        /**
         * @summary 在对象开始拖拽时触发的方法。
         * @event
         * @name draggable#onStartDrag
         * @param e {Object} 事件对象
         * @this jQuery对象
         * @default emptyFn
         */
        onStartDrag: function (e) {
        },
        /**
         * @summary 在对象拖拽过程中触发的方法。
         * @event
         * @name draggable#onDrag
         * @param e {Object} 事件对象
         * @this jQuery对象
         * @default emptyFn
         */
        onDrag: function (e) {
        },
        /**
         * @summary 在对象拖拽结束时触发的方法。
         * @event
         * @name draggable#onStopDrag
         * @param e {Object} 事件对象
         * @this jQuery对象
         * @default emptyFn
         */
        onStopDrag: function (e) {
        }
    };
    var _doDown = function (e) {
        if (!$.fn.draggable.isDragging){return false;}
        var target = e.data.target;
        var state = target.data(_cacheName);
        var opts = state.options;

        state.droppables = $('.droppable').filter(function () {
            return target != this;
        }).filter(function () {
            var accept = $.data(this[0], "draggable").options.accept;
            if (accept) {
                return $(accept).filter(function () {
                    return this == target;
                }).length > 0;
            } else {
                return true;
            }
        });

        var proxy = state.proxy;
        if (!proxy) {
            if (opts.proxy) {
                if (opts.proxy == 'clone') {
                    proxy = $(target).clone().insertAfter(target);
                } else {
                    proxy = opts.proxy.call(target,target);
                }
                state.proxy = proxy;
            } else {
                proxy = $(target);
            }
        }

        proxy.css('position', 'absolute');
        _drag(e);
        _applyDrag(e);

        opts.onStartDrag.call(target, e);
        return false;
    }

    var _doMove = function (e) {
        if (!$.fn.draggable.isDragging){return false;}
        var state = $.data(e.data.target[0], _cacheName);
        _drag(e);
        if (state.options.onDrag.call(e.data.target, e) != false) {
            _applyDrag(e);
        }

        var source = e.data.target;
        state.droppables.each(function () {
            var dropObj = $(this);
            if (dropObj.droppable('options').disabled) {
                return;
            }

            var p2 = dropObj.offset();
            if (e.pageX > p2.left && e.pageX < p2.left + dropObj.outerWidth()
                && e.pageY > p2.top && e.pageY < p2.top + dropObj.outerHeight()) {
                if (!this.entered) {
                    $(this).trigger('_dragenter', [source]);
                    this.entered = true;
                }
                $(this).trigger('_dragover', [source]);
            } else {
                if (this.entered) {
                    $(this).trigger('_dragleave', [source]);
                    this.entered = false;
                }
            }
        });

        return false;
    }

    var _doUp = function (e) {
        if (!$.fn.draggable.isDragging){
            _clearDragging();
            return false;
        }
        _doMove(e);

        var target = e.data.target;
        var state = target.data(_cacheName);
        var proxy = state.proxy;
        var opts = state.options;
        if (opts.revert) {
            if (_checkDrop(e) == true) {
                target.css({
                    position: e.data.startPosition,
                    left: e.data.startLeft,
                    top: e.data.startTop
                });
            } else {
                if (proxy) {
                    var left, top;
                    if (proxy.parent()[0] == document.body) {
                        left = e.data.startX - e.data.offsetWidth;
                        top = e.data.startY - e.data.offsetHeight;
                    } else {
                        left = e.data.startLeft;
                        top = e.data.startTop;
                    }
                    proxy.animate({
                        left: left,
                        top: top
                    }, function () {
                        _removeProxy(state,proxy);
                    });
                } else {
                    target.animate({
                        left: e.data.startLeft,
                        top: e.data.startTop
                    }, function () {
                        target.css('position', e.data.startPosition);
                    });
                }
            }
        } else {
            var parent=target.parent();
            var pos={left:0,top:0};
            var doc = $(document);
            if(e.data.startPosition=='fixed') {
                if (parent.is('body')) {
                    pos.left = doc.scrollLeft();
                    pos.top = doc.scrollTop();
                } else {
                    pos.left = doc.scrollLeft() - parent.scrollLeft();
                    pos.top = doc.scrollTop() - parent.scrollTop();
                }
            }else{
                if(!parent.is('body')) {
                    pos.left = doc.scrollLeft() - parent.scrollLeft();
                    pos.top = doc.scrollTop() - parent.scrollTop();
                }
            }
            target.css({
                position: e.data.startPosition,
                left: e.data.left-pos.left,
                top: e.data.top-pos.top
            });
            _checkDrop(e);
        }
        opts.onStopDrag.call(target, e);
        _clearDragging();
        return false;
    }

    var _clearDragging=function(){
        if ($.fn.draggable.timer){
            clearTimeout($.fn.draggable.timer);
            $.fn.draggable.timer = undefined;
        }
        $(document).unbind('.draggable');
        $.fn.draggable.isDragging = false;
        setTimeout(function(){
            $('body').css('cursor','');
        },100);
    }

    var _drag = function (e) {
        var state = $.data(e.data.target[0], _cacheName);
        var opts = state.options;
        var proxy = state.proxy;

        var dragData = e.data;
        var left = dragData.startLeft + e.pageX - dragData.startX;
        var top = dragData.startTop + e.pageY - dragData.startY;

        if (proxy) {
            if (proxy.parent()[0] == document.body) {
                if (opts.deltaX != null && opts.deltaX != undefined) {
                    left = e.pageX + opts.deltaX;
                } else {
                    left = e.pageX - e.data.offsetWidth;
                }
                if (opts.deltaY != null && opts.deltaY != undefined) {
                    top = e.pageY + opts.deltaY;
                } else {
                    top = e.pageY - e.data.offsetHeight;
                }
            } else {
                if (opts.deltaX != null && opts.deltaX != undefined) {
                    left += e.data.offsetWidth + opts.deltaX;
                }
                if (opts.deltaY != null && opts.deltaY != undefined) {
                    top += e.data.offsetHeight + opts.deltaY;
                }
            }
        }

        if (opts.axis.indexOf('h') != -1) {
            dragData.left = left;
        }
        if (opts.axis.indexOf('v') != -1) {
            dragData.top = top;
        }
    }

    var _applyDrag = function (e) {
        var state = $.data(e.data.target[0], _cacheName);
        var opts = state.options;
        var css = {};
        var proxy = state.proxy;
        if (!proxy) {
            proxy = $(e.data.target);
        }
        if(opts.axis.indexOf('h') != -1){
            css.left = e.data.left;
        }
        if(opts.axis.indexOf('v') != -1){
            css.top = e.data.top;
        }
        proxy.css(css);
        $('body').css('cursor',opts.cursor);
    }

    var _checkDrop = function (e) {
        var state = $.data(e.data.target[0], _cacheName);
        var opts = state.options;
        var proxy = state.proxy;
        var dropped = false;
        try {
            state.droppables.each(function () {
                var dropObj = $(this);
                if (dropObj.droppable('options').disabled) {
                    return;
                }
                var p2 = dropObj.offset();
                if (e.pageX > p2.left && e.pageX < p2.left + dropObj.outerWidth()
                    && e.pageY > p2.top && e.pageY < p2.top + dropObj.outerHeight()) {
                    if (opts.revert) {
                        $(e.data.target).css({
                            position: e.data.startPosition,
                            left: e.data.startLeft,
                            top: e.data.startTop
                        });
                    }
                    $(this).trigger('_drop', [e.data.target]);
                    _removeProxy(state,proxy);
                    dropped = true;
                    this.entered = false;
                    return false;
                }
            });
        } catch(e) {
        }
        if (!dropped && !opts.revert) {
            _removeProxy(state,proxy);
        }
        return dropped;
    }
    var _removeProxy=function(state,proxy){
        if (proxy){
            proxy.remove();
        }
        state.proxy = null;
    }
})(jQuery);

